package com.dd.ent.car.common.player;

import android.graphics.SurfaceTexture;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.os.Handler;
import android.os.Looper;
import android.text.TextUtils;
import android.view.Surface;
import android.view.SurfaceHolder;


import com.pp.ent.base.log.MLog;

import java.io.IOException;

/**
 * Author:LiuJianSheng
 * Date:2016/7/27
 * 封装MediaPlayer，包含MediaPlayer的状态管理
 */
public class MediaPlayerWrapper implements MediaPlayer.OnErrorListener,
        MediaPlayer.OnBufferingUpdateListener,
        MediaPlayer.OnInfoListener,
        MediaPlayer.OnCompletionListener,
        MediaPlayer.OnVideoSizeChangedListener,
        MediaPlayer.OnPreparedListener,
        MediaPlayer.OnSeekCompleteListener {
    public static final String TAG = "MediaPlayerWrapper";

    private Handler mMainThreadHandler = new Handler(Looper.getMainLooper());
    private PlayerStateManager mStateManager;
    private MediaPlayer mediaPlayer;
    private PlayerListener playerListener;
    private SurfaceHolder mSurfaceHolder;


    public MediaPlayerWrapper() {
        mStateManager = new PlayerStateManager(mMainThreadHandler);
        mediaPlayer = new MediaPlayer();
        initMediaPlayer(mediaPlayer);
    }

    private void initMediaPlayer(MediaPlayer mediaPlayer) {
        mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
        mediaPlayer.setScreenOnWhilePlaying(true);
        mediaPlayer.setOnErrorListener(this);
        mediaPlayer.setOnCompletionListener(this);
        mediaPlayer.setOnVideoSizeChangedListener(this);
        mediaPlayer.setOnInfoListener(this);
        mediaPlayer.setOnPreparedListener(this);
        mediaPlayer.setOnSeekCompleteListener(this);
        mediaPlayer.setOnBufferingUpdateListener(this);
    }

    public void attachAuxEffect(int effectId) {
        switch (getState()) {
            case INITIALIZED:
            case PREPARED:
            case LOADING:
            case STARTED:
            case PAUSED:
            case PLAYBACK_COMPLETED:
            case STOPPED:
            case PREPARING:
                MLog.debug(TAG, "attachAuxEffect--state=" + getState());
                mediaPlayer.attachAuxEffect(effectId);
                break;
            case IDLE:
            case ERROR:
            case RELEASE:
            default:
                MLog.error(TAG, "attachAuxEffect--state=" + getState());
                break;
        }
    }

    public void seekTo(int position) {
        switch (getState()) {
            case PREPARED:
            case LOADING:
            case STARTED:
            case PAUSED:
            case PLAYBACK_COMPLETED:
                MLog.debug(TAG, "seekTo--state=" + getState() + "|position=" + position);
                saftySeekTo(position);
                break;
            case RELEASE:
            case IDLE:
            case INITIALIZED:
            case STOPPED:
            case ERROR:
            case PREPARING:
            default:
                MLog.error(TAG, "seekTo--state=" + getState() + "|position=" + position);
                break;
        }
    }

    //一些机型中，用户拖动seekbar，直接拉到最后引起播放异常，所以不能seek到最后，只能提前一些时间
    private boolean saftySeekTo(int position) {
        int go = position;
        int duration = getDuration();
        if (duration > 0 && position == duration) {
            if (duration > 1000) {
                go = duration - 1000;
            }
        }
        mediaPlayer.seekTo(go);
        onPlayPositionChange(position);
        return true;
    }

    public void start() {
        checkUiThread();
        switch (getState()) {
            case PREPARED:
            case LOADING:
            case STARTED:
            case PAUSED:
            case PLAYBACK_COMPLETED:
            case STOPPED:
                MLog.debug(TAG, "start--state=" + getState());
                if (mSurfaceHolder != null) {
                    mediaPlayer.setDisplay(mSurfaceHolder);
                }
                mediaPlayer.start();
                setState(MediaPlayerState.STARTED);
                break;
            case IDLE:
            case INITIALIZED:
            case ERROR:
            case RELEASE:
            case PREPARING:
            default:
                MLog.error(TAG, "start--state=" + getState());
                break;
        }
    }

    public void pause() {
        checkUiThread();
        switch (getState()) {
            case STARTED:
            case PAUSED:
            case PLAYBACK_COMPLETED:
            case LOADING:
                MLog.debug(TAG, "pause--state=" + getState());
                mediaPlayer.pause();
                setState(MediaPlayerState.PAUSED);
                break;
            case IDLE:
            case INITIALIZED:
            case PREPARED:
            case PREPARING:
            case STOPPED:
            case ERROR:
            case RELEASE:
            default:
                MLog.error(TAG, "pause--state=" + getState());
                break;
        }
    }

    public void prepare() {
        checkUiThread();
        switch (getState()) {
            case INITIALIZED:
            case STOPPED:
                MLog.debug(TAG, "prepare--state=" + getState());
                try {
                    mediaPlayer.prepareAsync();
                    setState(MediaPlayerState.PREPARING);
                } catch (IllegalStateException e) {
                    reset();
                }
                break;
            case IDLE:
            case PREPARED:
            case PREPARING:
            case LOADING:
            case STARTED:
            case PAUSED:
            case PLAYBACK_COMPLETED:
            case ERROR:
            case RELEASE:
            default:
                MLog.error(TAG, "prepare--state=" + getState());
                break;
        }
    }

    public void setDataSource(String path) {
        checkUiThread();
        if (TextUtils.isEmpty(path)) {
            return;
        }
        switch (getState()) {
            case IDLE:
                MLog.debug(TAG, "setDataSource--state=" + getState() + "|path=" + path);
                try {
                    mediaPlayer.setDataSource(path);
                    setState(MediaPlayerState.INITIALIZED);
                } catch (IOException e) {
                    MLog.error(TAG, "setDataSource error --- " + e + "|path=" + path);
                    reset();
                }
                break;
            case ERROR:
                reset();
                setDataSource(path);
                break;
            case INITIALIZED:
            case PREPARED:
            case LOADING:
            case STARTED:
            case PAUSED:
            case PLAYBACK_COMPLETED:
            case STOPPED:
            case RELEASE:
            default:
                MLog.error(TAG, "setDataSource--state=" + getState());
                break;
        }
    }

    public void stop() {
        checkUiThread();
        switch (getState()) {
            case PREPARED:
            case LOADING:
            case STARTED:
            case PAUSED:
            case PLAYBACK_COMPLETED:
            case STOPPED:
            case PREPARING:
                MLog.debug(TAG, "stop--state=" + getState());
                mediaPlayer.stop();
                setState(MediaPlayerState.STOPPED);
                break;
            case IDLE:
            case INITIALIZED:
            case ERROR:
            case RELEASE:
            default:
                MLog.error(TAG, "stop--state=" + getState());
                break;
        }
    }

    public void reset() {
        checkUiThread();
        switch (getState()) {
            case INITIALIZED:
            case PREPARED:
            case LOADING:
            case STARTED:
            case PAUSED:
            case PLAYBACK_COMPLETED:
            case STOPPED:
            case ERROR:
            case PREPARING:
                MLog.debug(TAG, "reset--state=" + getState());
                if (mSurfaceHolder != null) {
                    mediaPlayer.setDisplay(null);
                }
                mediaPlayer.reset();
                setState(MediaPlayerState.IDLE);
                break;
            case IDLE:
                MLog.debug(TAG, "reset--state=" + getState());
                break;
            case RELEASE:
            default:
                MLog.error(TAG, "reset--state=" + getState());
                break;
        }
    }

    public void release() {
        MLog.debug(TAG, "release--state=" + getState());
        checkUiThread();
        switch (getState()) {
            case IDLE:
            case INITIALIZED:
            case PREPARED:
            case LOADING:
            case STARTED:
            case PAUSED:
            case PLAYBACK_COMPLETED:
            case STOPPED:
            case ERROR:
            case PREPARING:
                mediaPlayer.release();
                setState(MediaPlayerState.RELEASE);
                break;
            case RELEASE:
                break;
        }
    }

    public int getCurrentPosition() {
//        MLog.debug(TAG, "getCurrentPosition--state=" + getState());
        checkUiThread();
        switch (getState()) {
            case IDLE:
            case INITIALIZED:
            case PREPARED:
            case LOADING:
            case PREPARING:
            case STARTED:
            case PAUSED:
            case PLAYBACK_COMPLETED:
            case STOPPED:
                return mediaPlayer.getCurrentPosition();
            case ERROR:
            case RELEASE:
                break;
        }
        return 0;
    }

    public int getDuration() {
        MLog.debug(TAG, "getDuration--state=" + getState());
        switch (getState()) {
            case PREPARED:
            case LOADING:
            case STARTED:
            case PAUSED:
            case PLAYBACK_COMPLETED:
            case STOPPED:
                return mediaPlayer.getDuration();
            case IDLE:
            case INITIALIZED:
            case ERROR:
            case RELEASE:
            case PREPARING:
                break;
        }
        return 0;
    }

    public void setSurface(SurfaceTexture surfaceTexture) {
        MLog.debug(TAG, "setSurface--state=" + getState() + "|surface=" + surfaceTexture);
//        checkUiThread();
        if (getState() == MediaPlayerState.RELEASE) {
            return;
        }
        if (surfaceTexture == null) {
            mediaPlayer.setSurface(null);
        } else {
            mediaPlayer.setSurface(new Surface(surfaceTexture));
        }
    }

    public void setDisplay(SurfaceHolder holder) {
        MLog.debug(TAG, "setDisplay--state=" + getState() + "|holder=" + holder);
//        checkUiThread();
        if (getState() == MediaPlayerState.RELEASE) {
            return;
        }
        try {
            mediaPlayer.setDisplay(holder);
            mSurfaceHolder = holder;
        }catch (IllegalArgumentException e){
            MLog.debug(TAG,"The surface has been released ");
        }
    }

    public MediaPlayerState getState() {
        return mStateManager.getState();
    }

    public void setVolume(float leftVolumn, float rightVolumn) {
        checkUiThread();
        switch (getState()) {
            case IDLE:
            case INITIALIZED:
            case PREPARING:
            case PREPARED:
            case LOADING:
            case STARTED:
            case PAUSED:
            case PLAYBACK_COMPLETED:
            case STOPPED:
                MLog.debug(TAG, "setVolume--state=" + getState());
                mediaPlayer.setVolume(leftVolumn, rightVolumn);
                break;
            case ERROR:
            case RELEASE:
            default:
                MLog.error(TAG, "setVolume--state=" + getState());
                break;
        }
    }

    public void addStateChangeListener(MediaPlayerStateChangeListener listener) {
        mStateManager.addStateChangeListener(listener);
    }

    public void removeStateChangeListener(MediaPlayerStateChangeListener listener) {
        mStateManager.removeStateChangeListener(listener);
    }

    private void setState(MediaPlayerState state) {
        mStateManager.setState(state);
    }

    public void setPlayerListener(PlayerListener playerListener) {
        this.playerListener = playerListener;
    }

    @Override
    public void onBufferingUpdate(MediaPlayer mp, int percent) {
        if (playerListener != null) {
            playerListener.onBufferingUpdate(this, percent);
        }
    }

    @Override
    public void onCompletion(MediaPlayer mp) {
        MLog.debug(TAG, "onCompletion--");
        setState(MediaPlayerState.PLAYBACK_COMPLETED);
        if (playerListener != null) {
            playerListener.onCompletion(this);
        }
    }

    @Override
    public boolean onError(MediaPlayer mp, int what, int extra) {
        MLog.debug(TAG, "onError--what=" + what + "|extra=" + extra);
        //某些手机在某些情况下会回调unknown错误，过一会儿又继续播放，如果当前网络可用，则忽略unknown错误
        //但开启下面这个代码，会导致某些视频出错了，却一直在loading，永远无法结束，所以还是屏蔽掉这个山寨逻辑
        //if (what == MediaPlayer.MEDIA_ERROR_UNKNOWN && NetworkHelper.isNetworkAvailable(BrothersApplication.getInstance())) {
        //    return true;
        //}
        setState(MediaPlayerState.ERROR);
        if (playerListener != null) {
            return playerListener.onError(this, what, extra);
        }
        return true;
    }

    @Override
    public boolean onInfo(MediaPlayer mp, int what, int extra) {
        MLog.debug(TAG, "onInfo--what=" + what + "|extra=" + extra + "|state=" + getState());
        switch (what) {
            case MediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START:
                //加上暂停判断，三星S6暂停切后台，再切回来时会回调这个地方
                if (isPrepared() && getState() != MediaPlayerState.PAUSED) {
                    setState(MediaPlayerState.STARTED);
                }
                break;
            case MediaPlayer.MEDIA_INFO_BUFFERING_START:
                if (isPrepared() && getState() != MediaPlayerState.PAUSED) {
                    setState(MediaPlayerState.LOADING);
                }
                break;
            case MediaPlayer.MEDIA_INFO_BUFFERING_END:
                if (isPrepared() && getState() != MediaPlayerState.PAUSED) {
                    setState(MediaPlayerState.STARTED);
                }
                break;
        }
        if (playerListener != null) {
            return playerListener.onInfo(this, what, extra);
        }
        return true;
    }

    @Override
    public void onVideoSizeChanged(MediaPlayer mp, int width, int height) {
        if (playerListener != null) {
            playerListener.onVideoSizeChanged(this, width, height);
        }
    }

    @Override
    public void onPrepared(MediaPlayer mp) {
//        if (shouldNotifyOnPrepared.get()) {
        MLog.debug(TAG, "onPrepared--state=" + getState());
        setState(MediaPlayerState.PREPARED);
        if (playerListener != null) {
            playerListener.onPrepared(MediaPlayerWrapper.this);
        }
//        }
    }

    private void onPlayPositionChange(int newPosition) {
        if (playerListener != null) {
            playerListener.onPlayPositionChange(newPosition);
        }
    }

    @Override
    public void onSeekComplete(MediaPlayer mp) {
        if (playerListener != null) {
            playerListener.onSeekComplete(this);
        }
    }

    public boolean isPrepared() {
        return mStateManager.isPrepared();
    }

    public MediaPlayer getMediaPlayer() {
        return mediaPlayer;
    }

    private void checkUiThread() {
        boolean isUiThread = MediaPlayerUtils.isInUiThread();
        if (isUiThread) {
            throw new IllegalStateException("do not call in UI thread");
        }
    }
}
